package com.onpositive.mediawiki.propertyparser;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import com.onpositive.data.IPropertyConstants;
import com.onpositive.mediawiki.dataprocessors.AbstractDataProcessor;
import com.onpositive.units.ParsedProperty;
import com.onpositive.utils.IStringPoolProvider;
import com.onpositive.utils.StringPool;
import com.onpositive.wikistorage.PropertyAnalyzer;
import com.onpositive.wikistorage.PropertyStats;

public class ParsedCategory implements IStringPoolProvider {

	private HashMap<String, ParsedDocument> documents = new HashMap<String, ParsedDocument>();
	private HashSet<String> propertyNames = new HashSet<String>();
	private PropertyAnalyzer analyzer;
	private Map<String, PropertyCharacteristic> characteristicsMap = createCharacteristicsMap() ;
	private HashSet<String> links = new HashSet<String>();
	private HashSet<String> linkCaptions = new HashSet<String>();

	private HashMap<String, PropertyGroup> propertyGroups = new HashMap<String, PropertyGroup>();
	private String rootPath;
	
	private StringPool wikiRefsPool = new StringPool() ;

	public ParsedCategory(String rootPath) {
		this.rootPath=rootPath ;
	}
	
	protected Map<String, PropertyCharacteristic> createCharacteristicsMap() {
		return new HashMap<String, PropertyCharacteristic>();
	}

	public HashMap<String, PropertyGroup> getPropertyGroups() {
		return propertyGroups;
	}

	public void addPropertyGroup(String name, String parent) {
		propertyGroups.put(name, new PropertyGroup(name, parent, this));
	}

	public void addPropertyGroup(PropertyGroup group) {
		group.setCategory(this);
		propertyGroups.put(group.getName(), group);
	}

	public void addPropertyCharacteristic(PropertyCharacteristic pc) {
		pc.setCategory(this);
		characteristicsMap.put(pc.getCharacteristic(PropertyCharacteristic.CHAR_PROPERTY_NAME_LABEL),	pc);
	}

	public PropertyGroup getPropertyGroup(String name) {
		return propertyGroups.get(name);
	}

	public Map<String, PropertyCharacteristic> getChracteristicsMap() {
		characteristicsMap.remove(null);
		characteristicsMap.remove("");
		return characteristicsMap;
	}

	public PropertyCharacteristic getCharacteristics(String propertyName) {
		return characteristicsMap.get(propertyName);
	}

	public void setPropertyCharacteristic(String propertyName,
			PropertyCharacteristic pChar) {
		characteristicsMap.put(propertyName, pChar);
	}

	public void addParsedDocument(ParsedDocument doc) {
		doc.setCategory(this);
		documents.put(doc.getName(), doc);
		for (String s : doc.getProps().keySet())
			propertyNames.add(s);
	}

	public ParsedDocument getParsedDocument(String name) {
		return documents.get(name);
	}

	public Collection<ParsedDocument> getDocumentsList() {
		return documents.values();
	}
	
	public Collection<ParsedDocument> getSubcategoryDocuments( String categoryName ) {
		
		HashSet<ParsedDocument> rightDocs = new HashSet<ParsedDocument>() ;
		ParsedDocument root = this.getParsedDocument(categoryName) ;
		if( root == null )
			return new ArrayList<ParsedDocument>() ;
		
		rightDocs.add(root) ;
		HashSet<ParsedDocument> wrongDocs = new HashSet<ParsedDocument>() ;
		ArrayList<ParsedDocument> buffer = new ArrayList<ParsedDocument>() ;

		for( ParsedDocument pd : documents.values() )
			checkMembership( pd, root, rightDocs, wrongDocs ) ;
		
		return new ArrayList<ParsedDocument>( rightDocs ) ;
	}
	
	public StringPool getWikiRefsPool() {
		return wikiRefsPool;
	}

	private boolean checkMembership( ParsedDocument doc, ParsedDocument root , Set<ParsedDocument> right, Set<ParsedDocument> wrong )
	{
		if( right.contains( doc ) )
			return true ;
		
		if( wrong.contains( doc ) )
			return false ;
		
		//remember that roots of the parsed category have empty set of parents 
		try{		
		for( ParsedDocument parent : doc.getParentCategories() )
			if( checkMembership( parent, root, right, wrong) )
			{
				right.add( doc ) ;
				return true ;
			}
		}catch(Exception e)
		{
			e.printStackTrace() ;
		}
		
		wrong.add( doc ) ;
		return false ;
	}

	public ArrayList<String> getPropertiesList() {
		return new ArrayList<String>(propertyNames);
	}

	public HashSet<String> getPropertyNames() {
		return propertyNames;
	}

	public void collectStats() {
		if (analyzer == null) {
			analyzer = new PropertyAnalyzer();
			analyzer.processParsedCategory(this);
		}
	}

	public HashMap<String, PropertyStats> getStats() {
		if (analyzer == null)
			collectStats();

		return analyzer != null ? analyzer.getStatsMap() : null;
	}

	public void clearDocuments() {
		this.documents.clear();
	}

	public int getSize() {
		return documents.size();
	}

	
	public void applyDataProcessor( AbstractDataProcessor proc )
	{
		for( PropertyCharacteristic pc : getChracteristicsMap().values() )
			proc.inspect( pc ) ;
			
		for( ParsedDocument pd : this.documents.values() )
			for( ParsedProperty prop : pd.getProps().values() )
				proc.gatherStats( prop ) ;
		
		for( PropertyCharacteristic pc : getChracteristicsMap().values() )
			proc.applyChanges( pc ) ;
		
		for( ParsedDocument pd : this.documents.values() )
			for( ParsedProperty prop : pd.getProps().values() )
				proc.applyChanges( prop ) ;
	}

	

	public String getRootPath() {
		return rootPath;
	}
	
	@Override
	public StringPool getStringPool( String name )
	{
		if( name.equals(IPropertyConstants.WIKI_REFS_POOL_ID ) )
			return wikiRefsPool ;
		
		return null ;
	}
	
	public HashSet<String> getLinks() {
		return links;
	}
	
	public HashSet<String> getLinkCaptions() {
		return linkCaptions;
	}

	public void clearLinks(){
		links.clear() ;
		linkCaptions.clear() ;
	}
	
	

}
